#region Header

// Written by Tobias Lekman, 2008. For more information and contact details, see http://www.lekman.com.
// 
// File released under Microsoft Public License (Ms-PL). For full details see http://www.microsoft.com/opensource/licenses.mspx
// 
// Conditions and Limitations
// 
// (A) No Trademark License- This license does not grant you rights to use any contributors' name, logo, or trademarks.
// 
// (B) If you bring a patent claim against any contributor over patents that you claim are infringed by the software, your patent license from such contributor to the software ends automatically.
// 
// (C) If you distribute any portion of the software, you must retain all copyright, patent, trademark, and attribution notices that are present in the software.
// 
// (D) If you distribute any portion of the software in source code form, you may do so only under this license by including a complete copy of this license with your distribution. If you distribute any portion of the software in compiled or object code form, you may only do so under a license that complies with this license.
// 
// (E) The software is licensed "as-is." You bear the risk of using it. The contributors give no express warranties, guarantees or conditions. You may have additional consumer rights under your local laws which this license cannot change. To the extent permitted under your local laws, the contributors exclude the implied warranties of merchantability, fitness for a particular purpose and non-infringement. 

#endregion

#region Using Statements

using System;
using System.Diagnostics;
using System.Security.Principal;
using System.Text.RegularExpressions;
using CodePlex.Lekman.SharePoint.Testing.Properties;
using WatiN.Core;
using WatiN.Core.DialogHandlers;

#endregion

namespace CodePlex.Lekman.SharePoint.Testing
{
    /// <summary>
    /// Contains a WatIN object used to perform automated browser testing using Internet Explorer.
    /// </summary>
    public class BrowserTestFixture : IDisposable
    {
        #region Fields

        private readonly WindowsImpersonationContext impersonationContext;
        private IE browser;
        private bool isDisposed;

        #endregion

        #region Constructor

        /// <summary>
        /// Initializes a new instance of the <see cref="BrowserTestFixture"/> class.
        /// </summary>
        /// <param name="parent">The instance of the <see cref="SharePointTestFixture"/> that this class will be contained within.</param>
        public BrowserTestFixture(SharePointTestFixture parent)
        {
            ParentTestFixture = parent;
            WindowsIdentity identity = WindowsIdentity.GetCurrent();
            if (identity != null)
            {
                impersonationContext = identity.Impersonate();
            }
        }

        #endregion

        #region Properties

        /// <summary>
        /// Gets an instance of the <see cref="SharePointTestFixture"/> that this class is contained within.
        /// </summary>
        public SharePointTestFixture ParentTestFixture{get;private set;}

        /// <summary>
        /// Gets the shared instance of the browser used to perform the tests.
        /// </summary>
        protected IE Browser
        {
            get
            {
                if (browser == null)
                {
                    browser = new IE();
                    try
                    {
                        if (BrowserCredentials != null)
                        {
                            browser.DialogWatcher.Add(
                                new LogonDialogHandler(
                                    BrowserCredentials.UserName,
                                    BrowserCredentials.Password));
                        }
                    }
                    catch (NotImplementedException) {}
                }
                return browser;
            }
        }

        /// <summary>
        /// Gets or sets the user name and password used for the browser login handler dialog.
        /// </summary>
        protected BrowserLogOnCredentials BrowserCredentials{get;set;}

        #endregion

        #region Methods

        /// <summary>
        /// Returns a regular expression for matching an ID for a control.
        /// </summary>
        /// <param name="id">The original ID for the control.</param>
        /// <returns>A regular expression able to find the ID of the control independent of control hierarchy.</returns>
        public static Regex RegexForId(string id)
        {
            return new Regex(Resources.BrowserTestFixture_RegexForId_Pattern + id);
        }

        /// <summary>
        /// Ensures that the current browser URL can be connected to and contains no server errors.
        /// </summary>
        /// <returns>A <see cref="bool"/> flag indicating whether the page responded correctly or not.</returns>
        protected bool PageIsValid()
        {
            string message; //Ignored
            return PageIsValid(out message);
        }

        /// <summary>
        /// Ensures that a URL can be connected to and contains no server errors.
        /// </summary>
        /// <param name="uri">The Uri of the page to validate.</param>
        /// <param name="message">The detailed message regarding the connection to the site.</param>
        /// <returns>A <see cref="bool"/> flag indicating whether the page responded correctly or not.</returns>
        protected bool PageIsValid(Uri uri,
                                   out string message)
        {
            Browser.GoTo(uri);
            return PageIsValid(out message);
        }

        /// <summary>
        /// Ensures that the current browser URL can be connected to and contains no server errors.
        /// </summary>
        /// <param name="message">The detailed message regarding the connection to the site.</param>
        /// <returns>A <see cref="bool"/> flag indicating whether the page responded correctly or not.</returns>
        protected bool PageIsValid(out string message)
        {
            bool valid = true;
            message = Resources.BrowserTestFixture_PageIsValid_SuccessMessage;
            if (Browser.Url.Contains(Resources.BrowserTestFixture_PageIsValid_DnsErrorMarker))
            {
                message = Resources.BrowserTestFixture_PageIsValid_DnsErrorMessage;
                valid = false;
            }
            if (Browser.ContainsText(Resources.BrowserTestFixture_PageIsValid_ConfigDatabaseErrorMarker))
            {
                message = Resources.BrowserTestFixture_PageIsValid_ConfigDatabaseErrorMessage;
                valid = false;
            }
            if (Browser.ContainsText(Resources.BrowserTestFixture_PageIsValid_ServerErrorMarkerIE6) || //IIS6
                Browser.ContainsText(Resources.BrowserTestFixture_PageIsValid_ServerErrorMarkerIE7) || //IIS7
                Browser.ContainsText(Resources.BrowserTestFixture_PageIsValid_SharePointServerErrorMarker) // SharePoint
                )
            {
                message = Resources.BrowserTestFixture_PageIsValid_GenericServerErrorMarker;
                valid = false;
            }
            if (Browser.Title ==
                Resources.BrowserTestFixture_PageIsValid_404ErrorMarker)
            {
                message = Resources.BrowserTestFixture_PageIsValid_404ErrorMessage;
                valid = false;
            }
            Debug.WriteLine(message);
            return valid;
        }

        #endregion

        #region Implementation of IDisposable

        /// <summary>
        /// Disposes the managed and unmanaged resources instantiated within the class.
        /// </summary>
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        /// <summary>
        /// Disposes the managed and unmanaged resources instantiated within the class.
        /// </summary>
        /// <param name="disposing">Determines whether managed resources should be disposed.</param>
        protected virtual void Dispose(bool disposing)
        {
            if (!isDisposed)
            {
                if (browser != null)
                {
                    browser.Close();
                    impersonationContext.Undo();
                }
            }
            isDisposed = true;
        }

        #endregion
    }
}